package com.qianfeng.smsplatform.webmaster.service.impl;

//
//                            _ooOoo_  
//                           o8888888o  
//                           88" . "88  
//                           (| -_- |)  
//                            O\ = /O  
//                        ____/`---'\____  
//                      .   ' \\| |// `.  
//                       / \\||| : |||// \  
//                     / _||||| -:- |||||- \  
//                       | | \\\ - /// | |  
//                     | \_| ''\---/'' | |  
//                      \ .-\__ `-` ___/-. /  
//                   ___`. .' /--.--\ `. . __  
//                ."" '< `.___\_<|>_/___.' >'"".  
//               | | : `- \`.;`\ _ /`;.`/ - ` : | |  
//                 \ \ `-. \_ __\ /__ _/ .-` / /  
//         ======`-.____`-.___\_____/___.-`____.-'======  
//                            `=---='  
//  
//         .............................................  
//                  佛祖镇楼                  BUG辟易  
//          佛曰:  
//                  写字楼里写字间，写字间里程序员；  
//                  程序人员写程序，又拿程序换酒钱。  
//                  酒醒只在网上坐，酒醉还来网下眠；  
//                  酒醉酒醒日复日，网上网下年复年。  
//                  但愿老死电脑间，不愿鞠躬老板前；  
//                  奔驰宝马贵者趣，公交自行程序员。  
//                  别人笑我忒疯癫，我笑自己命太贱；  
//  


import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.qianfeng.smsplatform.webmaster.cache.BlackListCache;
import com.qianfeng.smsplatform.webmaster.constans.ResultCode;
import com.qianfeng.smsplatform.webmaster.events.UpdateBlackEvent;
import com.qianfeng.smsplatform.webmaster.exceptions.AddDataException;
import com.qianfeng.smsplatform.webmaster.exceptions.MyBaseException;
import com.qianfeng.smsplatform.webmaster.exceptions.UpdateDataException;
import com.qianfeng.smsplatform.webmaster.mapper.BlackListMapper;
import com.qianfeng.smsplatform.webmaster.pojo.CheckType;
import com.qianfeng.smsplatform.webmaster.pojo.MyAuthUser;
import com.qianfeng.smsplatform.webmaster.pojo.TAdminUser;
import com.qianfeng.smsplatform.webmaster.pojo.TBlackList;
import com.qianfeng.smsplatform.webmaster.service.BlackListService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by Jackiechan on 2021/10/25/17:05
 *
 * @author Jackiechan
 * @version 1.0
 * @since 1.0
 */
@Service
@Transactional
public class BlackListServiceImpl implements BlackListService {

    private BlackListMapper blackListMapper;

    private BlackListCache blackListCache;


    private ApplicationContext context;

    @Autowired
    public void setContext(ApplicationContext context) {
        this.context = context;
    }

    @Autowired
    public void setBlackListCache(BlackListCache blackListCache) {
        this.blackListCache = blackListCache;
    }

    @Autowired
    public void setBlackListMapper(BlackListMapper blackListMapper) {
        this.blackListMapper = blackListMapper;
    }

    @Override
    public TBlackList findBlackById(Long id) {
        //进行数据校验, 比如传递了一个负数过来, 还有必要查询数据库吗?,还有万一没有传递参数呢? 要查询数据库吗?
        //我们肯定不能浪费数据库的资源,不查询,不查询返回什么? 返回null?
        //按照我们的期望,这里必须要传递参数,并且要传递合法的参数,大于0的数字
        //如果你没有传递参数或者数字范围是负数,说明你没有按照我们的要求来做, 说明出现了问题,也就是有异常
        //如果返回null,那么如果传递的参数是合法的,但是数据不存在怎么办? 也返回null? 那就出现问题了返回null到底是参数有问题还是没查询到数据
        //因为当前方法的调用不一定是从什么地方过来的
        //所以当我们出现了和我们预期的要求不一致的时候 就应该抛异常,这就是已知的异常
        if (ObjectUtils.isEmpty(id) || id <= 0) {
            //传递的参数不符合我们的要求,抛出异常
            //抛什么异常?
            //不知道抛什么了, 抛自定义异常,因为自带的异常我们无法区分是什么情况
            throw new MyBaseException("传递的主键不合法", ResultCode.PK_NOT_ALLOW);
        }
//        return blackListMapper.findBlackById(id);
        return blackListCache.getByKey(id);
    }

    @Override
    public void addBlack(TBlackList black) {
        //数据校验
//        if (!CheckPhone.isPhone(black.getMobile())) {
//            //不是合理的手机号
//            //抛出异常
//            throw new AddDataException("手机号不符合规范", ResultCode.PHONE_NUM_ERROR);
//        }
        if (black.isNull(CheckType.ADD)) {
            throw new AddDataException("手机号不符合规范", ResultCode.PHONE_NUM_ERROR);
        }
        blackListMapper.addBlack(black);
//        //更新缓存
//        new Thread(){
//            @Override
//            public void run() {
//                blackListCache.getAllData().clear();
//                blackListCache.getAllData().addAll(blackListMapper.findAll());
//            }
//        }.start();
        //发布一个更新的事件
        context.publishEvent(new UpdateBlackEvent());
        System.err.println(Thread.currentThread().getName());

    }

    @Override
    @Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
    public PageInfo<TBlackList> findAll(int pageNum, int pageSize) {
        long start = System.currentTimeMillis();
        PageHelper.startPage(pageNum, pageSize);//开始分页
//        List<TBlackList> blackList = blackListMapper.findAll();//查询数据
//        PageInfo<TBlackList> pageInfo = new PageInfo<>(blackList);//封装数据
        List<TBlackList> allData = blackListCache.getAllData();//从缓存中获取所有的数据
        //根据你传递的是第几页,要几条,裁剪集合
//        //List<TBlackList> subList = allData.subList((pageNum - 1) * pageSize, pageNum * pageSize);
//        List<TBlackList> subList = allData.stream()
//                .skip((pageNum - 1) * pageSize)//跳过指定的条数, 也就是设置偏移量
//                .limit(pageSize)//设置期望要的最多的数据量
//                .collect(Collectors.toList());//转存到一个新的集合中
        //上面的代码我们发现了一个问题,就是返回的数据中包含了其他人的数据
        //我们需要过滤,我们需要先判断出哪些数据是当前用户可以看到的,然后再起个
        MyAuthUser authUser = (MyAuthUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
//        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
//        Object user = ((ServletRequestAttributes) requestAttributes).getRequest().getSession().getAttribute("user");
        //函数是一等公民
        List<TBlackList> tBlackLists = allData.stream().filter(black -> {
            //返回的是全局或者是创建者的数据,不能返回其他人的数据
            return black.getOwntype() == 1 || black.getCreater() == authUser.getId() || authUser.getType() == 1;
        }).collect(Collectors.toList());// 获取到符合当前用户能看到的所有的数据
        //这是按照用户能看到的数据切割出来的分页数据
        List<TBlackList> subList = tBlackLists.stream().skip((pageNum - 1) * pageSize).limit(pageSize).collect(Collectors.toList());

        PageInfo<TBlackList> pageInfo = new PageInfo<>(subList);
        pageInfo.setTotal(tBlackLists.size());//设置总条数
        long end = System.currentTimeMillis();
        System.err.println(end - start);
        return pageInfo;
    }

    @Override
    public void updateBlack(TBlackList blackList) {
        //先对数据进行校验
        //要更新 至少需要两个数据  第一个 主键,第二个更新的内容
        if (blackList.isNull(CheckType.UPDATE)) {
            //空的,也就是数据没有传递
            throw new UpdateDataException("更细必须传递主键或者手机号", ResultCode.DATA_ISNULL);
        }
        //执行 sql
        TBlackList queryData = blackListMapper.findBlackById(blackList.getId());//数据库中的数据
        if (blackList.getOwntype() != 1 && blackList.getCreater()!=queryData.getCreater()) {
            //既不是管理员,又不是所有者,代表没有权限更新
            throw new UpdateDataException("您没有权限更新当前数据", ResultCode.NO_PERMISSON);
        }
        blackListMapper.updateBlack(blackList);//
        //发布事件,更新缓存
        context.publishEvent(new UpdateBlackEvent());

    }

    @Override
    public void deleteBlackByIds(List<Integer> ids) {
        //根据 id 删除, 只要传递了 id 即可
        //如果传递的 id 中有自己创建的, 也有不是自己创建的, 该怎么办?
        //假如说我们选择删除能删除的部分,将不能删除的部分返回
        //如果当前用户是管理员,直接删
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        Object user = ((ServletRequestAttributes) requestAttributes).getRequest().getSession().getAttribute("user");
        if (((TAdminUser) user).getType() == 1) {
            //直接删除
            blackListMapper.deleteBlackByIds(ids);

        }else{
            //如果不是管理员,看看是否是自己创建的
            //先查询出这些要删除的数据是什么
            //判断数据的创建者和当前用户是不是同一个
            blackListMapper.deleteBlackByIdsAndCreater(ids, ((TAdminUser) user).getId());
        }

        context.publishEvent(new UpdateBlackEvent());//发布事件更新缓存

    }


}
